const fs = require('fs');
const path = require('path');
const rimraf = require('rimraf');
const xlsx = require('node-xlsx');
const { exit } = require('process');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const argv = yargs(hideBin(process.argv)).argv;

let source = argv.src;
if (!source) {
	console.error('没有指定源目录');
	exit(1);
}

let dist = argv.dist;
if (!dist) {
	console.error('没有指定导出目录');
	exit(1);
}

source = path.resolve(source);
dist = path.resolve(dist);

if (fs.existsSync(dist)) {
	rimraf(dist, (error) => {
		if (error) {
			console.error(error.message);
			exit(1);
		}

		start();
	});
} else {
	start();
}

function start() {
	fs.mkdirSync(dist);
	fs.readdir(source, function (err, fileList) {
		if (err) {
			console.error('获取文件失败:', err);
			exit(1);
		}

		let tableDefine = '';

		fileList.forEach((file) => {
			const data = parseFile(file);
			if (data) {
				// 将表格数据写入文件
				for (const sheetName in data) {
					if (Object.hasOwnProperty.call(data, sheetName)) {
						let sheetData = data[sheetName];
						const header = { ...sheetData.header };
						delete sheetData.header;
						fs.writeFileSync(path.join(dist, `${sheetName}Table.json`), JSON.stringify(sheetData, '', 4));

						tableDefine += `export interface I${sheetName.substr(0, 1).toUpperCase()}${sheetName.substring(
							1
						)}Data ${JSON.stringify(header, '', 4)} \r\n`;
					}
				}
			}

			fs.writeFileSync(path.join(dist, `table.d.ts`), tableDefine.replace(/[(\")]/g, ''));
		});
	});
}

function parseFile(file) {
	if (path.extname(file) !== '.xlsx' || file.indexOf('~$') !== -1 || file.indexOf('#') === 0) return null;

	const table = xlsx.parse(source + '/' + file);
	console.log('---- File: ', file);

	const checkSpecialKey = (target, keys) => {
		if (!target || !keys) return -1;
		const targetLen = target.length;
		for (let i = keys.length - 1; i >= 0; i--) {
			if (targetLen == 1) {
				if (String(keys[i]).lastIndexOf(target) === 0) {
					return i;
				}
			} else {
				if (String(keys[i]).startsWith(target)) {
					return i;
				}
			}
		}

		return -1;
	};

	let output = {};

	for (let i = 0, count = table.length; i < count; i++) {
		const sheet = table[i];
		const sheetNames = sheet.name.split('|');
		if (sheet.name.indexOf('#') >= 0 || sheetNames.length < 2) continue;

		const fileName = sheetNames[0]; //导出的文件名
		const keys = sheet.data[1]; //字段列表
		const types = sheet.data[2]; //字段的数据类型列表

		let obj = {},
			header = {};

		//找出不需要导出的字段
		let passCols = {};
		const descKeys = sheet.data[0];
		for (let c = 0; c < descKeys.length; c++) {
			if (descKeys[c] && descKeys[c].indexOf('#') !== -1) {
				passCols[c] = true;
			}
		}

		// row loops
		for (let a = 4; a < sheet.data.length; a++) {
			const row = sheet.data[a];

			//检查是否被导出
			const exportIndex = checkSpecialKey('export', keys);
			if (exportIndex !== -1 && ['true', '是', 'yes'].indexOf(String(row[exportIndex]).toLowerCase()) === -1) continue;

			//检查是否有主键
			const mainIndex = checkSpecialKey('*', keys);
			if (mainIndex === -1) continue;

			let contentObj;

			//检查是否有群组
			const groupIndex = checkSpecialKey('**', keys);

			if (groupIndex !== -1) {
				if (!obj[row[groupIndex]]) {
					obj[row[groupIndex]] = {};
				}
				contentObj = obj[row[groupIndex]][row[mainIndex]] = {};
			} else {
				contentObj = obj[row[mainIndex]] = {};
			}

			// col loops
			for (let b = 0; b < row.length; b++) {
				let key = keys[b];
				if (!key || key === 'export' || passCols[b]) continue;

				const { content, finalType } = handleData(row[b], types[b], key.startsWith('!'));
				if (typeof content !== 'undefined') {
					key = String(key).replace(/[(\*)(\!)]/g, '');
					contentObj[key] = content;
					if (!header.hasOwnProperty(key)) {
						header[key] = finalType;
					}
				}
			}
		}

		if (Object.hasOwnProperty.call(output, fileName)) {
			Object.assign(output[fileName], obj);
		} else {
			output[fileName] = obj;
		}

		output[fileName].header = header;

		// console.log(fileName);
	}

	return output;
}

//处理每个单元格
function handleData(data, type, necessary) {
	let def, result, finalType;

	if (type.indexOf('=')) {
		const typeArr = type.split('=');
		type = typeArr[0];
		def = typeArr[1];
	}

	if (typeof data === 'undefined' && def) {
		data = def;
	}

	// console.log(data, type, necessary);

	if (typeof data !== 'undefined' || necessary) {
		if (type === 'auto') {
			if (String(data).indexOf('[') === 0 && String(data).lastIndexOf(']') === String(data).length - 1) {
				type = 'array';
			} else if (String(data).indexOf('{') === 0 && String(data).lastIndexOf('}') === String(data).length - 1) {
				type = 'json';
			} else if (String(data).indexOf('.') !== -1) {
				type = 'float';
			} else if (!isNaN(Number(data))) {
				type = 'int';
			} else if (['是', '否', 'true', 'false', 'yes', 'no'].indexOf(data) !== -1) {
				type = 'bool';
			} else {
				type = 'str';
			}
		}

		switch (type) {
			case 'float':
				if (('' + data).indexOf('0000') >= 0) {
					result = +(+data).toFixed(6);
				} else {
					result = +data;
				}
				if (necessary && isNaN(result)) {
					result = 0;
				}
				finalType = 'number';
				break;
			case 'int':
				result = Math.floor(+data);
				if (necessary && isNaN(result)) {
					result = 0;
				}
				finalType = 'number';
				break;
			case 'array':
				result = eval(data);
				if (necessary && !result) {
					result = [];
				}
				finalType = 'any[]';
				break;
			case 'json':
				data = String(data).trim();
				result = eval(`(${data})`); //'(' + data + ')');
				if (necessary && !result) {
					result = {};
				}
				finalType = 'any';
				break;
			case 'bool':
				result = ['是', 'true', 'yes'].indexOf(data) !== -1;
				if (necessary && typeof result === 'undefined') {
					result = false;
				}
				finalType = 'boolean';
				break;
			case 'str':
				result = '' + data;
				if (necessary && !result) {
					result = '';
				}
				finalType = 'string';
				break;
			default:
				result = data;
				finalType = 'any';
				break;
		}
	}

	return { content: result, finalType };
}
